package org.rency.crawler.fetch.helper;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.rency.common.utils.domain.Extension;
import org.rency.common.utils.domain.Kvp;
import org.rency.common.utils.domain.SYSDICT;
import org.rency.common.utils.enums.CharsetEnum;
import org.rency.crawler.common.CrawlerConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 描述: ${TODO}<br>
 * 最近修改时间:2017/11/22 11:28<br>
 *
 * @author CaiyuRen
 * @version V1.0
 * @since 2017/11/22 11:28
 */
public class FetchHelper {

  private static final Logger logger = LoggerFactory.getLogger(FetchHelper.class);

  private FetchHelper(){}

  public static String appendParam2URL(String url, Extension parameter){
    if(parameter == null){
      return url;
    }

    StringBuilder queryString = new StringBuilder();
    boolean hasParam = false;
    for(Kvp kvp : parameter.getEntryList()){
      String name = kvp.getKey();
      String value = (String)kvp.getValue();
      // 忽略参数名或参数值为空的参数
      if (StringUtils.isNotBlank(name) && StringUtils.isNotBlank(value)) {
        if (hasParam) {
          queryString.append("&");
        } else {
          hasParam = true;
        }
        queryString.append(name).append("=");
        if(StringUtils.isNotBlank(CharsetEnum.UTF_8.getCode())){
          try {
            queryString.append(URLEncoder.encode(value, CharsetEnum.UTF_8.getCode()));
          } catch (UnsupportedEncodingException e) {
            //noinspection deprecation
            queryString.append(URLEncoder.encode(value));
          }
        }else{
          queryString.append(value);
        }
      }
    }
    if(queryString.length() > 0){
      queryString.insert(0, url+"?");
    }
    return url;
  }

  public static boolean isFile(Map<String, String> headers, List<String> typeList){
    if(MapUtils.isEmpty(headers) || CollectionUtils.isEmpty(typeList)){
      return false;
    }
    for(Entry<String, String> entry : headers.entrySet()){
      if(entry.getKey().toLowerCase().equals(CrawlerConstants.HTTP_HEADER_CONTENT_TYPE.toLowerCase())){
        String value = entry.getValue();
        for(String target : typeList){
          if(StringUtils.containsIgnoreCase(value,target)){
            return true;
          }
        }
      }
    }
    return false;
  }

  /**
   * 判断HTTP响应结果是否需要重试
   * </br>Created on 2016年4月29日
   * @param response HTTP响应
   * @return 是否
   */
  public static boolean needRetryRequest(CloseableHttpResponse response){
    switch(response.getStatusLine().getStatusCode()){
      case HttpStatus.SC_NOT_FOUND:
        return true;
      case HttpStatus.SC_REQUEST_TIMEOUT:
        return true;
      case HttpStatus.SC_LOCKED:
        return true;
      case 	HttpStatus.SC_BAD_GATEWAY:
        return true;
      case HttpStatus.SC_SERVICE_UNAVAILABLE:
        return true;
      case HttpStatus.SC_GATEWAY_TIMEOUT:
        return true;
      case HttpStatus.SC_INSUFFICIENT_STORAGE:
        return true;
      default:
        return false;
    }
  }

  /**
   * 判断HTTP响应结果是否需要重定向
   * </br>Created on 2016年4月29日
   * @param response HTTP响应
   * @return 是否
   */
  public static boolean needRedirectRequest(CloseableHttpResponse response){
    switch(response.getStatusLine().getStatusCode()){
      case HttpStatus.SC_MOVED_PERMANENTLY:
        return true;
      case HttpStatus.SC_MOVED_TEMPORARILY:
        return true;
      case HttpStatus.SC_TEMPORARY_REDIRECT:
        return true;
      default:
        return false;
    }
  }

  /**
   * 判断HTTP响应内容是否需要解析
   * @param response HTTP响应
   * @return 是否
   */
  public static boolean needParser(CloseableHttpResponse response){
    switch(response.getStatusLine().getStatusCode()){
      case HttpStatus.SC_NOT_MODIFIED:
        return false;
      case HttpStatus.SC_BAD_REQUEST:
        return false;
      case HttpStatus.SC_UNAUTHORIZED:
        return false;
      case HttpStatus.SC_FORBIDDEN:
        return false;
      default :
        return true;
    }
  }

  /**
   * 将URL中的参数转换为Extension格式
   * </br>Created on 2016年6月6日
   * @param queryString URL参数
   * @param destParam 参数集合
   */
  public static void convertUrlParam(String queryString,Extension destParam){
    if(StringUtils.isBlank(queryString)){
      return;
    }
    if(!StringUtils.contains(queryString, SYSDICT.SPLIT_CHAR_URL) && !StringUtils.contains(queryString, CrawlerConstants.EQUALS)){
      return;
    }
    List<String> sections = Arrays.asList(StringUtils.split(queryString,SYSDICT.SPLIT_CHAR_URL));
    for(String section : sections){
      if(StringUtils.contains(section,"=")){
        String[] keyValue = StringUtils.split(section, "=");
        if(keyValue.length != 2){
          continue;
        }
        destParam.add(keyValue[0].trim(), keyValue[1].trim());
      }
    }
  }

  /**
   * 获取页面字符编码格式
   * </br>Created on 2016年5月11日
   * @param entity 检测内容
   * @return 字符集
   */
  public static Charset getCharset(HttpEntity entity){
    ContentType contentType = ContentType.getOrDefault(entity);
    Charset charset = contentType.getCharset();
    if(charset == null){
      charset = ContentType.getOrDefault(entity).getCharset();
    }
    if(charset == null){
      return Charset.defaultCharset();
    }
    return charset;
  }

  /**
   * 计算权重平均值
   * @param identity 标识
   * @param uri uri
   * @param currentWeight 当前权重
   * @param queueCount 队列大小
   * @return 权重
   */
  public static double calculateWeightAverage(String identity,String uri,double currentWeight,int queueCount,double defaultWeight){
    if(currentWeight <= 0){
      return defaultWeight;
    }
    if(queueCount <= 0){
      return currentWeight;
    }
    double averageWeight = currentWeight + queueCount * CrawlerConstants.DEFAULT_PAGE_WEIGHT_STEP;
    logger.debug("计算权重平均值[{}-{}],当前权重:{},平均权重:{}.",identity,uri,currentWeight,averageWeight);
    return averageWeight;
  }

}
